package cn.enjoy.tool.utils.date;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Locale;
import java.util.Set;
import java.util.TimeZone;

import static java.time.temporal.TemporalAdjusters.lastInMonth;
import static java.time.temporal.TemporalAdjusters.nextOrSame;

/**
 * Java8 新日期操作
 *
 * @author K
 * @date 2020/11/9 11:01
 */
public class DateOperate {

    public static void main(String[] args) {
//        shiQu();
//        shunShi();
//        shiZhong();
//        bdRiQi();

//        riQiShiJianGSH();
        other();
    }
    /** java.time.ZoneId 是原有的java.util.TimeZone 类的替代品。*/
    public static void shiQu() {
        // 获取时区
        ZoneId shanghaiZoneId = ZoneId.of("Asia/Shanghai");
        ZoneId systemZoneId = ZoneId.systemDefault();
        // 获取所有可用时区id字符串字典
        Set<String> zoneIds = ZoneId.getAvailableZoneIds();
        // 老的TimeZone转换为ZoneId对象
        ZoneId oldToNewZoneId = TimeZone.getDefault().toZoneId();

        // 获取日期 和 时间
        LocalDateTime localDateTime = LocalDateTime.now();
        // 转换为时区的 日期 和 时间
        ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, shanghaiZoneId);

        // 通过时区偏移来计算
        ZoneOffset zoneOffset = ZoneOffset.of("+09:00");
        LocalDateTime localDateTime2 = LocalDateTime.now();
        OffsetDateTime offsetDateTime = OffsetDateTime.of(localDateTime2, zoneOffset);
        System.out.println();
    }

    /** Instant 瞬时 相当于System.currentTimeMillis(); 对秒做修改*/
    public static void shunShi() {
        Instant now = Instant.now();
        long l1 = now.toEpochMilli();
        long l = System.currentTimeMillis();
        System.out.println();
        /** now 瞬时加减
         * plusSeconds() 加
         * plusMillis()
         * plusNanos()
         * minusSeconds() 减
         * minusMillis()
         * minusNanos()
         */
    }

    /** Clock访问当前日期 和 时间，对时区敏感（对象关联Zone、Instant对象）。可以用来取代 System.currentTimeMillis() 来获取当前的微秒数。 */
    public static void shiZhong() {
        Clock clock = Clock.systemDefaultZone();
        long millis = clock.millis();
        Instant instant = clock.instant();
        Date legacyDate = Date.from(instant);
        Date date = new Date();
        System.out.println();
    }

    /** LocalDate 本地日期，无时区信息。 可以用来表示生日、节假日等 对日期做操作*/
    public static void bdRiQi() {
        LocalDate localDate = LocalDate.now();
        LocalDate localDate2 = LocalDate.of(2018, 3, 3);
        int year = localDate.getYear();
        Month month = localDate.getMonth();
        int value = month.getValue();
        int dayOfMonth = localDate.getDayOfMonth();
        int dayOfYear = localDate.getDayOfYear();
        DayOfWeek dayOfWeek = localDate.getDayOfWeek();
        int value1 = dayOfWeek.getValue();
        System.out.println();
        /** localDate 本地日期加减
         * plusDays()
         * plusWeeks()
         * plusMonths()
         * plusYears()
         * minusDays()
         * minusWeeks()
         * minusMonths()
         * minusYears()
         */
    }

    /** LocalTime 本地时间 无时区信息。对时间点处理，几点几分*/
    public static void bdShiJian() {
        LocalTime localTime = LocalTime.now();
        // ns（nanosecond）：纳秒，时间单位。一秒的十亿分之一，等于10的负9次方秒（1 ns = 10-9 s）。
        LocalTime localTime2 = LocalTime.of(21, 30, 59, 11001);
        /** localTime
         * getHour()
         * getMinute()
         * getSecond()
         * getNano()
         */

        /** localTime 加减
         * plusHours()
         * plusMinutes()
         * plusSeconds()
         * plusNanos()
         * minusHours()
         * minusMinutes()
         * minusSeconds()
         * minusNanos()
         */
    }

    /** LocalDateTime 本地日期时间，无时区信息。能操作日期 和 时间，上面两个的结合 */
    public static void bdRiQiShiJian() {
        LocalDateTime localDateTime = LocalDateTime.now();
        LocalDateTime localDateTime2 = LocalDateTime.of(2018, 11, 26, 13, 55, 36, 123);

        /**
         * getYear()
         * getMonth()
         * getDayOfMonth()
         * getDayOfWeek()
         * getDayOfYear()
         * getHour()
         * getMinute()
         * getSecond()
         * getNano()
         */

        /** localDateTime 加减
         * plusYears()
         * plusMonths()
         * plusDays()
         * plusHours()
         * plusMinutes()
         * plusSeconds()
         * plusNanos()
         * minusYears()
         * minusMonths()
         * minusDays()
         * minusHours()
         * minusMinutes()
         * minusSeconds()
         * minusNanos()
         */
    }

    /** ZonedDateTime 时区日期时间 ，有时区信息。 */
    public static void shiQuRiQiShiJian() {
        ZonedDateTime dateTime = ZonedDateTime.now();
        ZoneId zoneId = ZoneId.of("UTC+1");
        ZonedDateTime dateTime2 = ZonedDateTime.of(2015, 11, 30, 23, 45, 59, 1234, zoneId);
    }

    /** DateTimeFormatter 日期时间格式 解析和格式化日期时间 */
    public static void riQiShiJianGSH() {
        // DateTimeFormatter 类包含有预定义的格式化示例
        DateTimeFormatter formatter = DateTimeFormatter.BASIC_ISO_DATE;
        String formattedDate = formatter.format(LocalDate.now());
        String format = formatter.format(LocalDateTime.now());
        System.out.println(formattedDate);

        /**
         * 使用旧的Date对象时，我们用SimpleDateFormat进行格式化显示。使用新的LocalDateTime或ZonedLocalDateTime时，我们要进行格式化显示，就要使用DateTimeFormatter。
         * 和SimpleDateFormat不同的是，DateTimeFormatter不但是不变对象，它还是线程安全的。线程的概念我们会在后面涉及到。
         * 现在我们只需要记住：因为SimpleDateFormat不是线程安全的，使用的时候，只能在方法内部创建新的局部变量。而DateTimeFormatter可以只创建一个实例，到处引用。
         *
         * 创建DateTimeFormatter时，我们仍然通过传入格式化字符串实现：
         * DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
         * 格式化字符串的使用方式与SimpleDateFormat完全一致。
         */
        ZonedDateTime zdt = ZonedDateTime.now();
        DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm ZZZZ");
        System.out.println(formatter2.format(zdt));

        DateTimeFormatter zhFormatter = DateTimeFormatter.ofPattern("yyyy MMM dd EE HH:mm", Locale.CHINA);
        System.out.println(zhFormatter.format(zdt));

        DateTimeFormatter usFormatter = DateTimeFormatter.ofPattern("E, MMMM/dd/yyyy HH:mm", Locale.US);
        System.out.println(usFormatter.format(zdt));

        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(DateTimeFormatter.ISO_DATE.format(ldt));
        System.out.println(DateTimeFormatter.ISO_DATE_TIME.format(ldt));
        /**
         * 2019-09-15
         * 2019-09-15T23:16:51.56217
         */
    }

    /** Duration 期间，两个 Instant间的一段时间。 一个Duration实例是不可变的，当创建出对象后就不能改变它的值了。只能通过Duration的计算方法，出一个新的Durtaion对象，类似String */
    public static void qiJian() {
        Instant first = Instant.now();
        // wait some time while something happens
        Instant second = Instant.now();
        Duration duration = Duration.between(first, second);

        duration.toNanos();
        duration.getNano();
        /** 期间的时间，用不同单位表示
         * toNanos()
         * toMillis()
         * toMinutes()
         * toHours()
         * toDays()
         *
         * toNanos() 与  getNano() 不同， toNanos() 获得的是 Duration 整个时间共有多少纳秒，
         * 而 getNano() 只是获得这段时间中小于一秒的部分。
         * 没有 toSeconds() 方法，因为已经有 getSeconds() 这个方法能达到同样的功能了。
         */

        /**
         * plusNanos()
         * plusMillis()
         * plusSeconds()
         * plusMinutes()
         * plusHours()
         * plusDays()
         * minusNanos()
         * minusMillis()
         * minusSeconds()
         * minusMinutes()
         * minusHours()
         * minusDays()
         */
    }


    public static void other() {
        LocalDate date = LocalDate.of(2017, 1, 5); // 2017-01-05
        LocalDate date1 = date.withYear(2016); // 修改为 2016-01-05
        LocalDate date2 = date.withMonth(2); // 修改为 2017-02-05
        LocalDate date3 = date.withDayOfMonth(1); // 修改为 2017-01-01
        LocalDate date4 = date.plusYears(1); // 增加一年 2018-01-05
        LocalDate date5 = date.minusMonths(2); // 减少两个月 2016-11-05
        LocalDate date6 = date.plus(5, ChronoUnit.DAYS); // 增加5天 2017-01-10

        // 复杂日期时间操作 TemporalAdjuster 有很多示例
        LocalDate date7 = date.with(nextOrSame(DayOfWeek.SUNDAY)); // 返回下一个距离当前时间最近的星期日
        LocalDate date9 = date.with(lastInMonth(DayOfWeek.SATURDAY)); // 返回本月最后一个星期六

        // https://blog.csdn.net/liuwei0376/article/details/13620879 Java获取N天前，N天后的日期（如3天）

        // 如果还不能满足，可以自己定义
        LocalDate dateCustom = LocalDate.of(2017, 1, 5);
        dateCustom.with(temporal -> {
            // 当前日期
            DayOfWeek dayOfWeek = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
            // 正常情况下，每次增加一天
            int dayToAdd = 1;
            // 如果是星期五，增加三天
            if (dayOfWeek == DayOfWeek.FRIDAY) {
                dayToAdd = 3;
            }
            // 如果是星期六，增加两天
            if (dayOfWeek == DayOfWeek.SATURDAY) {
                dayToAdd = 2;
            }
            return temporal.plus(dayToAdd, ChronoUnit.DAYS);
        });
    }

}


